using System;
using System.Collections.Generic;
using UnityEngine;
public class AudioMgr : MonoBehaviour
{
    [Serializable]
    public class AudioData
    {
        public int id;
        public AudioSource comp;
        public float delay;
        public float duration;
        public float time;
        public bool isPlay;
    }

    private Transform root;
    private AudioSource _bgmAudio;
    private AudioClip _bgmClip;
    private AudioSource _oneShotAudio;
    private Dictionary<AudioClip, int> _lastPlay = new Dictionary<AudioClip, int>();
    private List<AudioData> _usedAudios = new List<AudioData>(30);

    private static AudioMgr _inst;
    public static AudioMgr Inst
    {
        get
        {
            if (_inst == null)
            {
                var go = new GameObject("AudioMgr");
                _inst = go.AddComponent<AudioMgr>();
                DontDestroyOnLoad(go);
            }

            return _inst;
        }
    }

    private void Awake()
    {
        root = transform;
        _bgmAudio = new GameObject("_bgmAudio").AddComponent<AudioSource>();
        _bgmAudio.transform.parent = root;
        _bgmAudio.loop = true;
        _oneShotAudio = new GameObject("_oneShotAudio").AddComponent<AudioSource>();
        _oneShotAudio.transform.parent = root;
    }

    private void Update()
    {
        foreach (var v in _usedAudios)
        {
            if (!v.isPlay || v.comp.loop)
                continue;

            v.time += Time.unscaledDeltaTime;
            if (v.time >= v.duration + v.delay) { StopAudio(v); }
        }
    }

    public void PlayBgmByName(string bgmName)
    {
        var clip = AssetsMgr.Inst.LoadAsset<AudioClip>(bgmName);
        PlayBGM(clip);
    }

    public void PlayBGM(AudioClip clip)
    {
        if (clip == null || clip == _bgmClip)
            return;

        _bgmClip = clip;
        PlayBgmAudio(clip);
    }

    public void PlayOneShot(AudioClip clip, float vol = 1f)
    {
        if (clip == null)
        {
            Debug.LogWarning("没有传入音效");
            return;
        }

        var fc = Time.frameCount;
        if (!_lastPlay.ContainsKey(clip))
        {
            _lastPlay.Add(clip, fc - 100);
        }

        if (fc - _lastPlay[clip] < 3)
            return;

        _lastPlay[clip] = fc;
        _oneShotAudio.PlayOneShot(clip, vol);
    }

    public void PlayOneShotByName(string audioName, float vol = 1f)
    {
        var clip = AssetsMgr.Inst.LoadAsset<AudioClip>(audioName);
        if (clip == null)
        {
#if UNITY_EDITOR
            Debug.LogError(name + " audio clip not found.");
#endif
            return;
        }

        PlayOneShot(clip, vol);
    }

    public void PlayBgmByName(string bgmName, float loopStart)
    {
        PlayBgmByName(bgmName);
        _bgmAudio.SetScheduledStartTime(loopStart);
    }

    private void PlayBgmAudio(AudioClip clip)
    {
        _bgmAudio.clip = clip;
        _bgmAudio.volume = 1;
        _bgmAudio.Play();
    }

    public int PlaySoundByName(string audioName, bool isLoop = false, float vol = 1f, float pitch = 1f, float delay = 0)
    {
        var clip = AssetsMgr.Inst.LoadAsset<AudioClip>(audioName);
        if (clip == null)
        {
#if UNITY_EDITOR
            Debug.LogError(audioName + " audio clip not found.");
#endif
            return -1;
        }

        return PlaySound(clip, isLoop, vol, pitch, delay);
    }

    /*
        播放音效 返回idx用于关闭
        isRole :播放角色的话音量不一样
    */
    public int PlaySound(AudioClip clip, bool isLoop = false, float vol = 1f, float pitch = 1f, float delay = 0)
    {
        if (clip == null)
        {
            Debug.LogWarning("没有传入音效");
            return -1;
        }

        // 相隔1帧以内不允许播放相同音频
        int fc = Time.frameCount;
        if (!_lastPlay.ContainsKey(clip))
            _lastPlay.Add(clip, fc);
        else if (fc - _lastPlay[clip] < 3)
            return -1;
        else
            _lastPlay[clip] = fc;

        var au = CreateAudio();
        float val = 1;
        au.comp.clip = clip;
        au.comp.volume = val * vol;
        au.comp.loop = isLoop;
        au.comp.pitch = pitch;
        au.delay = delay;
        au.duration = clip.length;
        au.time = 0;
        au.isPlay = true;
        if (delay > 0)
        {
            au.comp.PlayDelayed(delay);
        }
        else
        {
            au.comp.Play();
        }

        return au.id;
    }

    private AudioData CreateAudio()
    {
        for (var i = 0; i < _usedAudios.Count; i++)
        {
            if (!_usedAudios[i].isPlay)
                return _usedAudios[i];
        }

        var comp = new GameObject("audio").AddComponent<AudioSource>();
        comp.transform.parent = root;
        var au = new AudioData
        {
            id = _usedAudios.Count + 1,
            comp = comp
        };

        _usedAudios.Add(au);
        return au;
    }

    public void StopAudio(AudioData data)
    {
        data.comp.Stop();
        data.isPlay = false;
        data.time = 0;
    }
}